package com.web.kdl.config.security;

import com.web.kdl.config.security.components.*;
import com.web.kdl.util.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.util.List;


/**
 * @Author： shulibin
 * @Date： 2025/7/22 17:30
 * @Describe：
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private AuthenticationConfiguration authenticationConfiguration;

    @Autowired
    private RedisUtils redisUtils;

    @Value("${kdl-system.auth.jwt.expiration}")
    private Long expiration;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    @Bean
    public IgnoredUrlsConfig ignoredUrlsConfig() {
        return new IgnoredUrlsConfig();
    }

    @Bean
    public RestfulAccessDeniedHandler restfulAccessDeniedHandler() {
        return new RestfulAccessDeniedHandler();
    }
    @Bean
    public RestAuthenticationEntryPoint restAuthenticationEntryPoint() {
        return new RestAuthenticationEntryPoint();
    }
    /**
     *  权限配置 白名单... jwt认证
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http.authorizeRequests();
        List<String> urls = ignoredUrlsConfig().getUrls();
        // 循环白名单 进行放行
        ignoredUrlsConfig().getUrls().forEach(url -> registry.antMatchers(url).permitAll());

        // 允许可以请求Options cors
        registry.antMatchers(HttpMethod.OPTIONS).permitAll();

        // 其他任何请求需要身份认证
        registry
//               任何请求
                .anyRequest()
//               需要认证
                .authenticated()
                // 关闭csrf夸张请求伪造 因为现在是使用JWT来实现认证;
                        .and()
                                .csrf().disable()
                // 禁止session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                // 自定义权限拒绝处理类
                .and()
                .exceptionHandling()
               // 没权限访问的处理类
                .accessDeniedHandler(restfulAccessDeniedHandler())
                // 没有登录的处理类
                .authenticationEntryPoint(restAuthenticationEntryPoint())
                .and()
                .addFilterAt(new LoginFilter(authenticationManager(authenticationConfiguration), redisUtils, expiration), UsernamePasswordAuthenticationFilter.class)
                // 让校验Token的过滤器在身份认证过滤器之前
                        .addFilterBefore(new JwtAuthenticationFilter(redisUtils, expiration, ignoredUrlsConfig()), LoginFilter.class)
                .logout().logoutUrl("/logout").logoutSuccessHandler(new KdlLogoutSuccessHandler(redisUtils));
    }


//    @Override
//    protected void configure(HttpSecurity http) throws Exception {
//        http
//                .cors().and()
//                .csrf().disable() // 禁用CSRF保护
//                .authorizeRequests()
//                .antMatchers("/**").permitAll(); // 允许所有用户访问所有路径
//    }
















    private AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
        return config.getAuthenticationManager();
    }


}